#ifndef __MYSOCKET_H__
#define __MYSOCKET_H__

#include <vector>
#include <list>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <pthread.h>
#include <semaphore.h>
#include <atomic>
#include <map>

#include "comm.h"

#define LISTEN_BACKLOG 511 //socket可以排队的最大个数
#define MAX_EVENTS     512//epoll_wait一次最多接收的事件数量

typedef struct listening_s listening_t, *lplistening_t;
typedef struct connection_s connection_t, *lpconnection_t;
typedef class  MySocket     MySocket;

typedef void (MySocket::*event_handler_pt)(lpconnection_t c);

//与监听队列相关
struct listening_s {
	int port;
	int fd;
	lpconnection_t connection;
};

//与TCP连接池相关
struct connection_s {
	connection_s();
	virtual ~connection_s();

	void GetOneToUse();
	void PutOneToFree();

	int fd;
	lplistening_t listening;
	uint64_t      current_sequence;
	struct sockaddr sock_addr;

	event_handler_pt read_handler;
	event_handler_pt write_handler;

	uint32_t events;//和epoll事件相关

	
	//和收包相关
	unsigned char current_stat;//当前的收包状态
	char          data_head_info[_DATA_BUF_SIZE_];//保存收到的数据的包头信息
	char          *recv_buf;//接收数据缓冲区的头指针
	unsigned int  recv_len; //要收到多少数据
	char          *recv_mem_pointer;//new出来用于收包的内存首地址
	pthread_mutex_t logic_proc_mutex;//逻辑处理相关的互斥量

	//和发包相关
	char          *send_mem_pointer;//发送完后释放用，整个数据的头指针
	char          *send_buf;//发送数据缓冲区的头指针
	unsigned int  send_len;//需要发送的数据量
	std::atomic<int> throw_send_count;//如果发送缓冲区满，则用这个变量标记
		
	//和回收相关
	time_t in_recy_time;

	//和心跳包相关
	time_t last_ping_time;


	//和网络安全相关
	uint64_t flood_kick_last_time;//flood攻击上次收包数量
	int      flood_attack_count;//flood攻击在该时间内收到包的次数统计
	std::atomic<int> send_count;//发送列表中的数目???

	lpconnection_t next;//指向连接池的下个内存位置
};

//消息头
typedef struct _STRUC_MSG_HEADER {
	lpconnection_t connect;
	uint64_t       current_sequence;//收到数据包时记录对应的连接的序号
}STRUC_MSG_HEADER,*LPSTRUC_MSG_HEADER;

//socket相关
class MySocket {
public:
	MySocket();
	virtual ~MySocket();
	virtual bool Initialize();        //初始化函数(在父进程中执行)
	virtual bool InitializeSubproc(); //初始化函数(在子进程中执行)
	virtual void ShutdownSubproc();   //关闭退出函数(子进程)

	void PrintInfo();//打印统计信息

	virtual void ThreadRecvProcFunc(char *msg_buf);//处理客户端请求
	virtual void ProcPingTimeOutChecking(LPSTRUC_MSG_HEADER msg, time_t current_time);

	//与epoll相关
	int EpollInit();
	int EpollProcessEvent(int timer);
	int EpollOperEvent(int fd, uint32_t event_type, uint32_t flag, int back_action, lpconnection_t connect);
protected:
	//和数据发送相关
	void MsgSend(char *send_buf);
	void ActiveCloseSocketProc(lpconnection_t connect);//主动关闭一个连接(包含将连接送入连接回收队列中)
	
	//和收包发包相关
	size_t pkg_head_len_;
	size_t msg_head_len_;

	//和时间相关
	int if_timeout_kick_;//时间到时，直接踢人
	int wait_time_;//多少秒检测一次是否心跳超时
	
private:
	void ReadConf();
	bool OpenListeningSocket();
	void CloseListeningSocket();
	bool SetNonblocking(int sockfd);
	//通用处理函数
	void EventAccept(lpconnection_t old_connect);
	void CloseConnection(lpconnection_t connect);
	void ReadRequestHandler(lpconnection_t connect);
	void WriteRequestHandler(lpconnection_t connect);
	
	
	ssize_t RecvProc(lpconnection_t connect, char *buff, ssize_t buf_len);//接收从客户端来的数据专用函数
	void WaitRequestHandlerProcHead(lpconnection_t connect, bool &isflood);//包头收完后的处理
	void WaitRequestHandlerProcBody(lpconnection_t connect, bool &isflood);//包体收完后的处理
	void ClearMsgSendQueue();       //处理发送消息队列
	ssize_t SendProc(lpconnection_t connect, char *buff, ssize_t size);//将数据发送到客户端
	//获取对端信息相关
	size_t SockNtop(struct sockaddr *sa, int port, u_char *text, size_t len);
	//和连接池相关
	
	void InitConnection();
	void ClearConnection();
	lpconnection_t GetConnection(int sock);//从连接池中获取一个空闲连接
	void FreeConnection(lpconnection_t Connect);//归还参数Connect代表的连接到连接池中
	void InRecyConnectQueue(lpconnection_t Connect);//延迟回收连接
	
	//和定时器相关
	void AddToTimerQueue(lpconnection_t connect);//设置踢出时钟(向map表中增加内容)
	time_t GetEarliestTime();//取出最早的时间返回
	LPSTRUC_MSG_HEADER RemoveFirstTimer();//从时间队列中移除最早的时间
	LPSTRUC_MSG_HEADER GetOverTimeTimer(time_t current_time);//根据当前时间，找到超时时间

	void DeleteFromTimerQueue(lpconnection_t connect);
	void ClearAllFromTimerQueue();//清除时间队列中的所有内容


	//和线程相关
	static void* ServerSendQueueThread(void *thread_data);//专门用来发送数据的线程
	static void* ServerRecyConnectionThread(void *thread_data);//专门用于回收连接的线程
	static void* ServerTimerQueueMonitorThread(void *thread_data);

	//和网络安全相关
	bool TestFlood(lpconnection_t connect);

	struct ThreadItem {
		pthread_t _handle;
		MySocket *this_;
		bool if_running;
		ThreadItem(MySocket *this_):this_(this_),if_running(false){}
		~ThreadItem(){}
	};

	int worker_connections_;
	int listen_port_count_;//监听端口的数量
	int epoll_handle_;
	struct epoll_event events_[MAX_EVENTS];
	
	std::vector<lplistening_t> listen_socket_list_;//监听套接字队列
	//和连接池相关的成员变量
	std::list<lpconnection_t> connection_list_;
	std::list<lpconnection_t> free_connection_list_;
	std::atomic<int> total_connections_;
	std::atomic<int> free_connections_;
	pthread_mutex_t connection_mutex_;
	//和延迟回收相关
	pthread_mutex_t recy_connect_queue_mutex_;
	std::list<lpconnection_t> recy_connection_list_;
	std::atomic<int> totol_recy_connections_;
	int recy_connection_wait_time_;//等待这些秒数后回收连接

	//发送消息队列
	std::list<char *> msg_send_queue_;
	std::atomic<int> send_msg_queue_count_;
	//多线程相关
	std::vector<ThreadItem *> thread_vector_;
	pthread_mutex_t send_message_queue_mutex_;
	sem_t sem_event_send_queue_;
	//时间相关
	int if_kick_time_count_;//是否开启踢人时钟
	pthread_mutex_t time_queue_mutex_;
	std::multimap<time_t, LPSTRUC_MSG_HEADER> time_queue_map_;

	size_t current_size_;//时间队列的尺寸
	time_t timer_value_; //当前计时队列头部时间值

	//在线用户相关
	std::atomic<int> online_user_count_;
	//网络安全相关
	int flood_attack_enable_;//flood攻击检测是否开启
	unsigned int flood_time_interval_;//每次收到数据包的时间间隔
	int flood_kick_count_;//累计多少次开踢

	//统计相关
	time_t last_print_time_;
	int    discard_send_pkg_count_;//丢弃发送数据包的数量
};

#endif

